package com.piggy.logi.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.piggy.common.core.constant.SecurityConstants;
import com.piggy.common.core.exception.GlobalException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.utils.StringUtils;
import com.piggy.common.core.utils.sql.SqlUtil;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.satoken.utils.SecurityUtils;
import com.piggy.im.domain.bo.SmsMessage;
import com.piggy.im.domain.bo.SysPublishMsgBo;
import com.piggy.im.enums.MsgLevelType;
import com.piggy.im.enums.MsgType;
import com.piggy.im.enums.ReceiverType;
import com.piggy.im.service.SmsMsgSend;
import com.piggy.im.service.StationMsgSend;
import com.piggy.logi.sys.api.domain.LogiSysUser;
import com.piggy.logi.sys.api.utils.ZhongYouApiUtil;
import com.piggy.logi.sys.api.vo.LogiSysDeptExtVo;
import com.piggy.logi.sys.bo.*;
import com.piggy.logi.sys.domain.*;
import com.piggy.logi.sys.enums.*;
import com.piggy.logi.sys.mapper.LogiWaybillMapper;
import com.piggy.logi.sys.service.*;
import com.piggy.logi.sys.vo.*;
import com.piggy.sys.api.RemoteDistrictService;
import com.piggy.sys.api.enums.SmsTemplateEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 运单信息Service业务层处理
 */
@Slf4j
@Service
public class LogiWaybillServiceImpl extends ServiceImpl<LogiWaybillMapper, LogiWaybill> implements ILogiWaybillService {

    @Resource
    private ILogiWaybillValueAddService logiWaybillValueAddService;
    @Resource
    private ILogiWaybillSignService logiWaybillSignService;
    @Resource
    private ILogiWaybillFeeService logiWaybillFeeService;
    @Resource
    private ILogiWaybillCarrierService logiWaybillCarrierService;
    @Resource
    private RemoteDistrictService remoteDistrictService;
    @Resource
    private ILogiWaybillGoodSourceService logiWaybillGoodSourceService;
    @Resource
    private ILogiSysDeptService logiSysDeptService;
    @Resource
    private ILogiScheduleService logiScheduleService;
    @Resource
    private ILogiSysOrderSetService logiSysOrderSetService;
    @Resource
    private ILogiSysWaybillConfigService logiSysWaybillConfigService;
    @Resource
    private ILogiPickupOrderService pickupOrderService;
    @Resource
    private ILogiCustomerService logiCustomerService;
    @Resource
    private ILogiDrayageService logiDrayageService;
    @Resource
    private ILogiWaybillReceiptLogService receiptLogService;
    @Resource
    private ILogiWaybillReceivableService logiWaybillReceivableService;
    @Resource
    private ILogiWaybillPayableService logiWaybillPayableService;
    @Resource
    private ILogiWaybillAgentPayService logiWaybillAgentPayService;
    @Resource
    private ILogiWaybillKefuLogService kefuLogService;
    @Resource
    private ILogiCustomerCheckBillService logiCustomerCheckBillService;
    @Resource
    private ILogiScheduleFeeService logiScheduleFeeService;
    @Resource
    private ILogiScheduleService scheduleService;

    @Resource
    private ILogiSysUserService userService;

    @Resource
    private ILogiCarrierDriverService driverService;

    @Resource
    private ILogiWaybillLogService waybillLogService;

    @Resource
    private ILogiGoodOrderService goodOrderService;

    @Resource
    private ILogiWaybillOrderRelateService waybillOrderRelateService;

    @Resource
    private ILogiGoodOrderService logiGoodOrderService;

    @Override
    public LogiWaybillExtVo queryById(Long id) {
        LogiWaybillExtVo vo = getVoById(id, LogiWaybillExtVo.class);
        if (ObjectUtil.isEmpty(vo)) {
            return vo;
        }
        List<LogiWaybillExtVo> waybillList = Lists.newArrayList(vo);
        fillDate(waybillList);
        return waybillList.get(0);
    }

    @Override
    public TableDataInfo<LogiWaybillExtVo> queryPageList(LogiWaybillQueryBo bo) {
        PageInfo<LogiWaybillExtVo> result = startPage(bo).doSelectPageInfo(() -> {
            List<LogiWaybillExtVo> voList = baseMapper.selectWaybillList(buildQueryWrapper(bo));
            fillDate(voList);
        });
        return PageUtils.buildDataInfo(result);
    }

    public void fillDate(List<LogiWaybillExtVo> waybillList) {
        if (CollUtil.isEmpty(waybillList)) {
            return;
        }
        List<String> districtIds = Lists.newArrayList();
        waybillList.forEach(waybill -> {
            districtIds.add(waybill.getShipDistrictId().toString());
            districtIds.add(waybill.getDeliveryDistrictId().toString());
        });
        // 获取地址数据
        Map<String, String> districtNameMap = remoteDistrictService.getDistrictMap(districtIds, SecurityConstants.INNER).getData();

        // 获取货源数据
        List<Long> waybillIds = waybillList.stream().map(LogiWaybillExtVo::getWaybillId).collect(Collectors.toList());
        List<LogiWaybillGoodSource> orderGoodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
        Map<Long, List<LogiWaybillGoodSource>> goodSourceExtVoMap = orderGoodSourceList.stream().collect(Collectors.groupingBy(LogiWaybillGoodSource::getWaybillId));

        // 获取费用信息
        List<LogiWaybillFee> waybillFees = logiWaybillFeeService.getByWaybillIds(waybillIds);
        Map<Long, LogiWaybillFee> waybillFeeMap = waybillFees.stream().collect(Collectors.toMap(LogiWaybillFee::getWaybillId, Function.identity(), (a, b) -> a));

        // 获取增值服务
        List<LogiWaybillValueAdd> waybillValueAdds = logiWaybillValueAddService.getByWaybillIds(waybillIds);
        Map<Long, LogiWaybillValueAdd> waybillValueAddMap = waybillValueAdds.stream().collect(Collectors.toMap(LogiWaybillValueAdd::getWaybillId, Function.identity(), (a, b) -> a));

        // 获取承运商信息
        List<LogiWaybillCarrier> waybillCarriers = logiWaybillCarrierService.getByWaybillIds(waybillIds);
        Map<Long, LogiWaybillCarrier> waybillCarrierMap = waybillCarriers.stream().collect(Collectors.toMap(LogiWaybillCarrier::getWaybillId, Function.identity(), (a, b) -> a));

        // 获取调度信息
        LogiScheduleQueryBo queryBo = new LogiScheduleQueryBo();
        queryBo.setScheduleNos(waybillList.stream().map(LogiWaybillExtVo::getScheduleNo).distinct().collect(Collectors.toList()));
        List<LogiScheduleExtVo> scheduleExtVos = logiScheduleService.queryList(queryBo, true);
        Map<String, LogiScheduleExtVo> scheduleExtVoMap = scheduleExtVos.stream().collect(Collectors.toMap(LogiScheduleExtVo::getScheduleNo, Function.identity(), (a, b) -> a));

        // 获取短驳信息
        LogiDrayageQueryBo drayageBo = new LogiDrayageQueryBo();
        drayageBo.setDrayageNos(waybillList.stream().map(LogiWaybillExtVo::getDrayageNo).distinct().collect(Collectors.toList()));
        List<LogiDrayageExtVo> drayageExtVos = logiDrayageService.queryList(drayageBo, true);
        Map<String, LogiDrayageExtVo> drayageExtVoMap = drayageExtVos.stream().collect(Collectors.toMap(LogiDrayageExtVo::getDrayageNo, Function.identity(), (a, b) -> a));

        // 获取提货信息
        List<LogiPickupOrderExtVo> pickupVos = pickupOrderService.queryList(new LogiPickupOrderQueryBo().setWaybillIds(waybillIds), true);
        Map<Long, LogiPickupOrderExtVo> pickupMap = pickupVos.stream().collect(Collectors.toMap(LogiPickupOrderVo::getWaybillId, Function.identity(), (a, b) -> a));

        // 获取签收信息
        List<LogiWaybillSignVo> waybillSigns = logiWaybillSignService.queryList(new LogiWaybillSignQueryBo().setWaybillIds(waybillIds));
        Map<Long, LogiWaybillSignVo> waybillSignMap = waybillSigns.stream().collect(Collectors.toMap(LogiWaybillSignVo::getWaybillId, Function.identity(), (a, b) -> a));

        // 获取网点数据
        List<Long> deptIds = Lists.newArrayList();
        List<Long> customerIds = Lists.newArrayList();
        for (LogiWaybillExtVo item : waybillList) {
            customerIds.add(item.getShipId());
            customerIds.add(item.getDeliveryId());
            deptIds.add(item.getShipNetId());
            deptIds.add(item.getDeliveryNetId());
        }
        deptIds = deptIds.stream().distinct().collect(Collectors.toList());
        List<LogiSysDeptExtVo> sysDeptExtVos = logiSysDeptService.selectDeptByIds(deptIds);
        Map<Long, LogiSysDeptExtVo> sysDeptExtVoMap = sysDeptExtVos.stream().collect(Collectors.toMap(LogiSysDeptExtVo::getDeptId, Function.identity()));

        // 发、收货方数据
        customerIds = customerIds.stream().distinct().collect(Collectors.toList());
        List<LogiCustomerExtVo> customerExtVoList = logiCustomerService.queryList(new LogiCustomerQueryBo().setCustomerIdList(customerIds));
        Map<Long, LogiCustomerExtVo> customerExtVoMap = customerExtVoList.stream().collect(Collectors.toMap(LogiCustomerExtVo::getCustomerId, Function.identity()));

        // 挂失信息
        List<LogiWaybillKefuLogVo> lrLogList = kefuLogService.getLrLogList(waybillIds, 1);
        Map<Long, LogiWaybillKefuLogVo> logExtVoMap = new HashMap<>();
        lrLogList.stream().peek(Any -> {
            if (!logExtVoMap.containsKey(Any.getWaybillId())) {
                logExtVoMap.put(Any.getWaybillId(), Any);
            }
        }).collect(Collectors.toList());

        // 关联订单
        List<LogiWaybillOrderRelate> waybillOrderRelateList = waybillOrderRelateService.listByWaybillIds(waybillIds);
        Map<Long, List<LogiWaybillOrderRelate>> waybillOrderRelateMap = waybillOrderRelateList.stream().collect(Collectors.groupingBy(LogiWaybillOrderRelate::getWaybillId, Collectors.toList()));

        waybillList.forEach(waybill -> {
            waybill.setShipDistrictName(districtNameMap.get(waybill.getShipDistrictId().toString()));
            waybill.setDeliveryDistrictName(districtNameMap.get(waybill.getDeliveryDistrictId().toString()));
            waybill.setScheduleVo(scheduleExtVoMap.get(waybill.getScheduleNo()));
            waybill.setDrayageVo(drayageExtVoMap.get(waybill.getDrayageNo()));

            if (goodSourceExtVoMap.get(waybill.getWaybillId()) != null) {
                waybill.setGoodSourceList(BeanUtil.copyToList(goodSourceExtVoMap.get(waybill.getWaybillId()), LogiWaybillGoodSourceVo.class));
            }
            if (waybillFeeMap.get(waybill.getWaybillId()) != null) {
                waybill.setWaybillFee(waybillFeeMap.get(waybill.getWaybillId()));
            }
            if (waybillValueAddMap.get(waybill.getWaybillId()) != null) {
                waybill.setWaybillValueAdd(waybillValueAddMap.get(waybill.getWaybillId()));
            }
            if (waybillCarrierMap.get(waybill.getWaybillId()) != null) {
                waybill.setWaybillCarrier(waybillCarrierMap.get(waybill.getWaybillId()));
            }

            if (customerExtVoMap.get(waybill.getShipId()) != null) {
                waybill.setShipName(customerExtVoMap.get(waybill.getShipId()).getCustomerName());
            }
            if (customerExtVoMap.get(waybill.getDeliveryId()) != null) {
                waybill.setDeliveryName(customerExtVoMap.get(waybill.getDeliveryId()).getCustomerName());
            }
            if (sysDeptExtVoMap.get(waybill.getShipNetId()) != null) {
                waybill.setShipNetName(sysDeptExtVoMap.get(waybill.getShipNetId()).getDeptName());
            }
            if (sysDeptExtVoMap.get(waybill.getDeliveryNetId()) != null) {
                waybill.setDeliveryNetName(sysDeptExtVoMap.get(waybill.getDeliveryNetId()).getDeptName());
            }
            if (waybillSignMap.get(waybill.getWaybillId()) != null) {
                waybill.setSignVo(waybillSignMap.get(waybill.getWaybillId()));
            }
            if (logExtVoMap.get(waybill.getWaybillId()) != null) {
                waybill.setLrLogVo(logExtVoMap.get(waybill.getWaybillId()));
            }
            if (waybillOrderRelateMap.get(waybill.getWaybillId()) != null) {
                List<LogiGoodOrder> goodOrderList = waybillOrderRelateMap.get(waybill.getWaybillId())
                        .stream().map(a -> goodOrderService.getById(a.getGoodOrderId())).collect(Collectors.toList());
                waybill.setGoodOrderList(goodOrderList);
            }
            waybill.setPickupVo(pickupMap.get(waybill.getWaybillId()));
        });
    }

    @Override
    public List<LogiWaybillExtVo> queryList(LogiWaybillQueryBo bo) {
        List<LogiWaybillExtVo> extVoList = baseMapper.selectWaybillList(buildQueryWrapper(bo));
        fillDate(extVoList);
        return extVoList;
    }

    private QueryWrapper<LogiWaybill> buildQueryWrapper(LogiWaybillQueryBo bo) {
        QueryWrapper<LogiWaybill> lqw = Wrappers.query();
        //lqw.eq(ObjectUtil.isNotEmpty(bo.getDeptId()), "bill.dept_id", bo.getDeptId());
        lqw.like(bo.getOutCode() != null, "bill.out_code", bo.getOutCode());
        lqw.like(bo.getOldOutCode() != null, "bill.old_out_code", bo.getOldOutCode());
        lqw.eq(bo.getRefund() != null, "bill.refund", bo.getRefund());
        lqw.eq(bo.getShipId() != null, "bill.ship_id", bo.getShipId());
        lqw.like(StrUtil.isNotBlank(bo.getScheduleNo()), "bill.schedule_no", bo.getScheduleNo());
        lqw.like(StrUtil.isNotBlank(bo.getDrayageNo()), "bill.drayage_no", bo.getDrayageNo());
        lqw.eq(bo.getShipNetId() != null, "bill.ship_net_id", bo.getShipNetId());
        lqw.eq(bo.getStatus() != null, "bill.status", bo.getStatus());
        lqw.eq(bo.getInvoiceStatus() != null, "bill.invoice_status", bo.getInvoiceStatus());
        lqw.in(CollUtil.isNotEmpty(bo.getStatusList()), "bill.status", bo.getStatusList());
        lqw.in(CollUtil.isNotEmpty(bo.getScheduleList()), "bill.schedule_status", bo.getScheduleList());
        lqw.notIn(CollUtil.isNotEmpty(bo.getNotStatusList()), "bill.status", bo.getNotStatusList());
        lqw.in(CollUtil.isNotEmpty(bo.getDrayageList()), "bill.drayage_status", bo.getDrayageList());
        if (StringUtils.isNotBlank(bo.getShipPlanTimeStr())) {
            lqw.eq("DATE_FORMAT(bill.ship_plan_time, '%Y-%m-%d')", bo.getShipPlanTimeStr());
        }
        if (StringUtils.isNotBlank(bo.getCreateTimeStr())) {
            lqw.eq("DATE_FORMAT(bill.create_time, '%Y-%m-%d')", bo.getCreateTimeStr());
        }
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getShipPlanTimeStart(), bo.getShipPlanTimeStartEnd()), "date_format(bill.ship_plan_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getShipPlanTimeStart(), bo.getShipPlanTimeStartEnd());
        lqw.apply(ObjectUtil.isAllNotEmpty(bo.getCreateTimeStart(), bo.getCreateTimeEnd()), "date_format(bill.create_time,'%y%m%d') between date_format({0},'%y%m%d') and date_format({1},'%y%m%d') ", bo.getCreateTimeStart(), bo.getCreateTimeEnd());
        lqw.eq(bo.getCargoControl() != null, "bill.cargo_control", bo.getCargoControl());
        lqw.eq(bo.getEnableStatus() != null, "bill.enable_status", bo.getEnableStatus());
        lqw.eq(bo.getCargoControlStatus() != null, "bill.cargo_control_status", bo.getCargoControlStatus());
        if (StrUtil.isNotBlank(bo.getCustomerName())) {
            lqw.and(lqw1 -> lqw1.like("c1.customer_name", bo.getCustomerName()).or().like("c2.customer_name", bo.getCustomerName()));
        }
        lqw.apply(ObjectUtil.isNotEmpty(bo.getDeptId()), StrUtil.format("bill.dept_id in (SELECT dept_id FROM logi_sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ))", bo.getDeptId(), bo.getDeptId()));
        lqw = lqw.orderByAsc("IF(bill.status != 100,1,2)").orderByAsc("bill.status").orderByDesc("bill.create_time");
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LogiWaybillExtVo insertByAddBo(LogiWaybillEditExtBo bo) {
        // 判断关联的线上订单是否已取消
        List<LogiGoodOrder> logiGoodOrders = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(bo.getGoodOrderIdList())) {
            logiGoodOrders = goodOrderService.listByIds(bo.getGoodOrderIdList());
            List<String> messageList = CollUtil.newArrayList();
            for (LogiGoodOrder logiGoodOrder : logiGoodOrders) {
                if (logiGoodOrder.getGoodOrderType() == 1 && logiGoodOrder.getStatus() == GoodOrderStatusEnum.CANCEL.getCode()) {
                    messageList.add(String.format("关联的线上订单【{}】已取消", logiGoodOrder.getOrderCode()));
                } else if (ObjectUtil.isNotNull(logiGoodOrder.getWaybillId())) {
                    messageList.add(String.format("关联的线上订单【{}】已关联运单【{}】", logiGoodOrder.getOrderCode(), logiGoodOrder.getOutCode()));
                }
            }
            if (CollUtil.isNotEmpty(messageList)) {
                throw new GlobalException(String.format("{}，请重新选择", String.join("，", messageList)));
            }
        }

        LogiWaybill add = BeanUtil.toBean(bo, LogiWaybill.class);
        add.setStatus(bo.getSubmitted() == 1 ? WaybillStatusEnum.SUBMITED.getCode() : WaybillStatusEnum.WAIT_SUBMIT.getCode());
//        add.setOutCode(logiSysOrderSetService.getOutCode(bo.getDeptId()));
        add.setOutCode(logiSysWaybillConfigService.getOutCode(SecurityUtils.getMainDeptId()));
        LogiWaybillValueAdd valueAdd = BeanUtil.toBean(bo.getWaybillValueAdd(), LogiWaybillValueAdd.class);
        LogiWaybillFee fee = BeanUtil.toBean(bo.getWaybillFee(), LogiWaybillFee.class);
        LogiWaybillCarrier carrier = BeanUtil.toBean(bo.getWaybillCarrier(), LogiWaybillCarrier.class);
        List<LogiWaybillGoodSource> goodSourceList = BeanUtil.copyToList(bo.getGoodSourceList(), LogiWaybillGoodSource.class);
        validEntityBeforeSave(add);
        add.setWaybillId(null);
        save(add);
        if (valueAdd != null) {
            valueAdd.setId(null);
            valueAdd.setDeptId(add.getDeptId());
            valueAdd.setWaybillId(add.getWaybillId());
            logiWaybillValueAddService.save(valueAdd);
        }

        if (fee != null) {
            fee.setId(null);
            fee.setWaybillId(add.getWaybillId());
            fee.setDeptId(add.getDeptId());
            logiWaybillFeeService.save(fee);
        }

        if (carrier != null) {
            carrier.setId(null);
            carrier.setWaybillId(add.getWaybillId());
            carrier.setDeptId(add.getDeptId());
            logiWaybillCarrierService.save(carrier);
        }

        if (CollUtil.isNotEmpty(goodSourceList)) {
            goodSourceList.forEach(item -> {
                item.setId(null);
                item.setWaybillId(add.getWaybillId());
                item.setDeptId(add.getDeptId());
            });
            logiWaybillGoodSourceService.saveBatch(goodSourceList);
        }

        if (CollUtil.isNotEmpty(logiGoodOrders)) {
            List<LogiWaybillOrderRelate> waybillOrderRelateList = CollUtil.newArrayList();
            for (LogiGoodOrder logiGoodOrder : logiGoodOrders) {
                logiGoodOrder.setWaybillId(add.getWaybillId());
                logiGoodOrder.setOutCode(add.getOutCode());
                LogiWaybillOrderRelate waybillOrderRelate = new LogiWaybillOrderRelate();
                waybillOrderRelate.setDeptId(add.getDeptId());
                waybillOrderRelate.setWaybillId(add.getWaybillId());
                waybillOrderRelate.setOutCode(add.getOutCode());
                waybillOrderRelate.setGoodOrderId(logiGoodOrder.getGoodOrderId());
                waybillOrderRelate.setOrderCode(logiGoodOrder.getOrderCode());
                waybillOrderRelate.setGoodOrderType(logiGoodOrder.getGoodOrderType());
                waybillOrderRelateList.add(waybillOrderRelate);
            }
            logiGoodOrderService.updateBatchById(logiGoodOrders);
            waybillOrderRelateService.saveBatch(waybillOrderRelateList);
        }

        // 增加运单控货状态处理
        processWaybillControl(add.getWaybillId());
        // 增加结算信息
        addOrUpdateWaybillReceivable(add, valueAdd, fee);
        return queryById(add.getWaybillId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByEditBo(LogiWaybillEditExtBo bo) {
        LogiWaybill update = BeanUtil.toBean(bo, LogiWaybill.class);
        LogiWaybillValueAdd valueAdd = BeanUtil.toBean(bo.getWaybillValueAdd(), LogiWaybillValueAdd.class);
        LogiWaybillFee fee = BeanUtil.toBean(bo.getWaybillFee(), LogiWaybillFee.class);
        LogiWaybillCarrier carrier = BeanUtil.toBean(bo.getWaybillFee(), LogiWaybillCarrier.class);
        validEntityBeforeSave(update);

        List<LogiWaybillGoodSource> waybillGoodSources = BeanUtil.copyToList(bo.getGoodSourceList(), LogiWaybillGoodSource.class);
        if (CollUtil.isNotEmpty(waybillGoodSources)) {
            waybillGoodSources.forEach(goodSourceEditBo -> {
                goodSourceEditBo.setWaybillId(update.getWaybillId());
            });
            logiWaybillGoodSourceService.batchUpdateByWaybillId(update.getWaybillId(), waybillGoodSources);
        }

        updateById(update);

        if (ObjectUtil.isNotEmpty(valueAdd)) {
            valueAdd.setWaybillId(update.getWaybillId());
            valueAdd.setDeptId(update.getDeptId());
            logiWaybillValueAddService.updateByUK(valueAdd);
        }
        if (ObjectUtil.isNotEmpty(fee)) {
            fee.setWaybillId(update.getWaybillId());
            fee.setDeptId(update.getDeptId());
            logiWaybillFeeService.updateByUK(fee);
        }
        if (ObjectUtil.isNotEmpty(carrier)) {
            carrier.setWaybillId(update.getWaybillId());
            carrier.setDeptId(update.getDeptId());
            logiWaybillCarrierService.updateByUK(carrier);
        }
        if (ObjectUtil.isAllNotEmpty(valueAdd, fee)) {
            addOrUpdateWaybillReceivable(getById(update.getWaybillId()), valueAdd, fee);
        }

        // 增加运单控货状态处理
        //processWaybillControl(update.getWaybillId());

        return true;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(LogiWaybill entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void operateWaybill(Integer type, Long waybillId) {
        if (type != WaybillStatusEnum.SUBMITED.getCode() && type != WaybillStatusEnum.CANCEL.getCode()) {
            throw new GlobalException("参数不合法");
        }
        LogiWaybill waybill = getById(waybillId);
        if (waybill == null) {
            throw new GlobalException("运单数据不存在");
        }
        LogiWaybill update = new LogiWaybill();
        // 提交
        if (type == WaybillStatusEnum.SUBMITED.getCode() && waybill.getStatus() != WaybillStatusEnum.WAIT_SUBMIT.getCode()) {
            throw new GlobalException(String.format("当前运单是[%s]状态,不能做提交操作", WaybillStatusEnum.get(waybill.getStatus()).getInfo()));
        }

        // 取消
        if (type == WaybillStatusEnum.CANCEL.getCode()) {

            if (!Lists.newArrayList(ScheduleStatusEnum.CANCEL_SCHEDULE.getCode(), ScheduleStatusEnum.UNSCHEDULED.getCode(), ScheduleStatusEnum.SCHEDULED.getCode()).contains(waybill.getScheduleStatus()))
                throw new GlobalException(String.format("当前运单调度是[%s]状态,不能做取消操作", ScheduleStatusEnum.get(waybill.getScheduleStatus()).getInfo()));

            if (!Lists.newArrayList(WaybillStatusEnum.WAIT_SUBMIT.getCode(), WaybillStatusEnum.SUBMITED.getCode(), WaybillStatusEnum.PICKUPING.getCode()).contains(waybill.getStatus()))
                throw new GlobalException(String.format("当前运单是[%s]状态,不能做取消操作", WaybillStatusEnum.get(waybill.getStatus()).getInfo()));

            update.setScheduleNo("");
            update.setScheduleStatus(ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());
            update.setDrayageStatus(DrayageStatusEnum.CANCEL.getCode());
            checkAndUpdateStatus(waybill.getScheduleNo(), WaybillStatusEnum.CANCEL);
            LogiWaybillExtVo vo = queryById(waybillId);

            // 增加运单日志
            //waybillLogService.addLog(vo.getWaybillId(), WaybillStatusEnum.CANCEL.getCode());
            //billPushStationMsg(vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.CANCEL.getInfo(), WaybillStatusEnum.CANCEL.getNextInfo());
            //billPushSms(vo.getWaybillId(), vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.CANCEL.getInfo(), WaybillStatusEnum.CANCEL.getNextInfo());

            // 删除订单关联的运单信息
            deleteOrderRelate(waybillId);
        }

        update.setWaybillId(waybillId);
        update.setStatus(type);
        updateById(update);
        // 检查是否运单全部装载了
        /*if (type == WaybillStatusEnum.CANCEL.getCode()) {
            checkAndUpdateStatus(waybill.getScheduleNo(), WaybillStatusEnum.LOADED);
        }*/
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidById(Long id, Boolean isValid) {
        LogiWaybill logiWaybill = getById(id);
        if (isValid) {
            log.info("运单删除操作 id:{}", id);
            //1、删除运单范围：待提货、已取消状态下运单。2、删除勾选运单为单选，并且弹窗二次确认。
            if (logiWaybill == null || WaybillStatusEnum.notDelete(logiWaybill.getStatus())) {
                throw new GlobalException("该运单禁止删除");
            }
        }
        removeById(id);
        logiWaybillValueAddService.removeByUK(logiWaybill.getDeptId(), id);
        logiWaybillFeeService.removeByUK(logiWaybill.getDeptId(), id);
        logiWaybillCarrierService.removeByUK(logiWaybill.getDeptId(), id);
        logiWaybillReceivableService.removeByUK(logiWaybill.getDeptId(), id);
        logiWaybillPayableService.removeByUK(logiWaybill.getDeptId(), id);
        logiWaybillAgentPayService.removeByUK(logiWaybill.getDeptId(), id);
        // 删除订单关联的运单信息
        deleteOrderRelate(logiWaybill.getWaybillId());
        return true;
    }


    @Override
    public TableDataInfo<LogiWaybillExtVo> dispatchList(OperationDispatchQueryBo queryBo) {
        PageInfo<LogiWaybillExtVo> result = startPage(queryBo).doSelectPageInfo(() -> {
            List<LogiWaybillExtVo> voList = baseMapper.selectWaybillList(buildOperationDispatchWrapper(queryBo));
            fillDate(voList);
        });
        return PageUtils.buildDataInfo(result);
    }

    private QueryWrapper<LogiWaybill> buildOperationDispatchWrapper(OperationDispatchQueryBo queryBo) {
        QueryWrapper<LogiWaybill> lqw = buildQueryWrapper(queryBo);
        // 1、待发运单状态：待装车、待发车、在途中会在待发运单可见。2、可根据条件查询运单。（见原型）
//         lqw.in(queryBo.getStatus() == null, "bill.status", WaybillStatusEnum.getDispatchList());
        lqw.eq(queryBo.getShipDistrictId() != null, "bill.ship_district_id", queryBo.getShipDistrictId());
        lqw.eq(queryBo.getDeliveryDistrictId() != null, "bill.delivery_district_id", queryBo.getDeliveryDistrictId());
        return lqw;
    }

    /**
     * 1、选择待装车运单装车，二次确认。前提：该运单完成车辆调度。
     * 2、确认装车对应车次车辆上运单在装载运单可见。
     * 3、确认装车运单状态为“待发车”
     * 4、装车的运单可在对应车次运单列表进行取消、卸车操作。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void load(List<Long> waybillIds, Long loadId, Integer type) {
        List<LogiWaybill> waybillList = listByIds(waybillIds);
        if (type == 0) {
            /*List<String> outCodes = waybillList.stream().filter(item -> item.getStatus() != WaybillStatusEnum.PICKUPING.getCode()).map(LogiWaybill::getOutCode).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(outCodes)) {
                throw new GlobalException("运单[" + JSONUtil.toJsonStr(outCodes) + "状态不合法,存在运单未提货");
            }*/
            throw new GlobalException("装车请求已经停用");
        }

        List<LogiWaybill> updateBOs = Lists.newArrayList();
        waybillIds.forEach(waybillId -> {
            LogiWaybill updateBO = new LogiWaybill();
            updateBO.setWaybillId(waybillId);
            if (type == 0) {
                updateBO.setLoadId(loadId);
//                updateBO.setStatus(WaybillStatusEnum.LOADED.getCode());
            } else if (type == 1) {
                updateBO.setUnLoadId(loadId);
            }

            updateBOs.add(updateBO);
        });
        this.updateBatchById(updateBOs);

//        List<String> schNos = waybillList.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
//        checkAndUpdateStatus(schNos, WaybillStatusEnum.LOADED);
    }

    /**
     * 1、取消装车只能选择单个运单。
     * 2、针对已装车运单，取消装车返回上一状态。“待装车”
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelLoad(Long loadId, Integer type) {
        List<LogiWaybill> waybillList = baseMapper.selectByLoadId(loadId);

        if (type == 0) {
            /*List<String> outCodes = waybillList.stream().filter(item -> item.getStatus() != WaybillStatusEnum.LOADED.getCode()).map(LogiWaybill::getOutCode).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(outCodes)) {
                throw new GlobalException("运单" + JSONUtil.toJsonStr(outCodes) + "状态不合法,存在运单未装车");
            }*/
            throw new GlobalException("取消装车请求已经停用");
        }

        List<LogiWaybill> updateBOs = Lists.newArrayList();
        waybillList.forEach(waybill -> {
            LogiWaybill updateBO = new LogiWaybill();
            updateBO.setWaybillId(waybill.getWaybillId());

            if (type == 0) {
                updateBO.setLoadId(0L);
                updateBO.setStatus(WaybillStatusEnum.PICKUPING.getCode());
            } else if (type == 1) {
                updateBO.setUnLoadId(0L);
            }

            updateBOs.add(updateBO);
        });
        this.updateBatchById(updateBOs);
    }

    /**
     * 1、选运单发车跳转发车车次。
     * 2、弹出显示司机、车辆、协议、运单信息二次确认。（见原型需求）。
     * 3、对应发车车次若存在多个调度运单，若其它运单未装车会提示“存在未装车运单”，所有调度运单装车之后才可弹窗确认发车。
     * 4、确认发车运单状态为“在途中”。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void depart(String scheduleNo) {
        List<LogiWaybill> waybillList = baseMapper.selectByScheduleNo(scheduleNo);
        List<String> outCodes = waybillList.stream().filter(item -> {
            if (item.getStatus() != WaybillStatusEnum.PICKUPING.getCode()) {
                throw new GlobalException("存在未提货运单:[" + item.getOutCode() + "]");
            }
//            return item.getStatus() != WaybillStatusEnum.LOADED.getCode();
            return item.getStatus() == WaybillStatusEnum.PICKUPING.getCode();
        }).map(LogiWaybill::getOutCode).collect(Collectors.toList());
        inTransit(waybillList, outCodes);
    }

    @Transactional(rollbackFor = Exception.class)
    public void inTransit(List<LogiWaybill> waybillList, List<String> outCodes) {
        List<LogiWaybill> updateBOs = Lists.newArrayList();
        waybillList.forEach(waybill -> {
            LogiWaybill updateBO = new LogiWaybill();
            updateBO.setWaybillId(waybill.getWaybillId());
            updateBO.setStatus(WaybillStatusEnum.DEPARTURE.getCode());

            updateBOs.add(updateBO);
            // 新增或修改应付记录
            addOrUpdateWaybillPayable(waybill);
        });
        this.updateBatchById(updateBOs);
    }

    /**
     * 1、取消针对当前车次整体取消。
     * 2、取消状态返回上一状态。
     * 3、根据GPS若车辆行驶1公里之外，或发车一小时后不可取消。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelDepart(String scheduleNo) {
        List<LogiWaybill> waybillList = baseMapper.selectByScheduleNo(scheduleNo);
        List<String> outCodes = waybillList.stream().filter(item -> {
            // 根据GPS若车辆行驶1公里之外，或发车一小时后不可取消。
            if (item.getUpdateTime().before(DateUtil.offsetHour(new Date(), -1).toJdkDate())) {
                throw new GlobalException("发车一小时后不可取消");
            }
            return item.getStatus() != WaybillStatusEnum.DEPARTURE.getCode();
        }).map(LogiWaybill::getOutCode).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(outCodes)) {
            throw new GlobalException("运单" + JSONUtil.toJsonStr(outCodes) + "状态不合法,存在运单不在发车中");
        }

        List<LogiWaybill> updateBOs = Lists.newArrayList();
        waybillList.forEach(waybill -> {
            LogiWaybill updateBO = new LogiWaybill();
            updateBO.setWaybillId(waybill.getWaybillId());
//            updateBO.setStatus(WaybillStatusEnum.LOADED.getCode());
            updateBO.setStatus(WaybillStatusEnum.PICKUPING.getCode());
            updateBOs.add(updateBO);
        });
        this.updateBatchById(updateBOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void arrived(String scheduleNo) {
        List<LogiWaybill> waybillList = baseMapper.selectByScheduleNo(scheduleNo);
        List<String> outCodes = waybillList.stream().filter(item -> item.getStatus() != WaybillStatusEnum.DEPARTURE.getCode()).map(LogiWaybill::getOutCode).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(outCodes)) {
            throw new GlobalException("运单" + JSONUtil.toJsonStr(outCodes) + "状态不合法,存在运单未发车");
        }

        List<LogiWaybill> updateBOs = Lists.newArrayList();
        waybillList.forEach(waybill -> {
            LogiWaybill updateBO = new LogiWaybill();
            updateBO.setWaybillId(waybill.getWaybillId());
            updateBO.setStatus(WaybillStatusEnum.ARRIVAL.getCode());

            updateBOs.add(updateBO);
        });
        this.updateBatchById(updateBOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelArrived(String scheduleNo) {
        List<LogiWaybill> waybillList = baseMapper.selectByScheduleNo(scheduleNo);
        List<String> outCodes = waybillList.stream().filter(item -> {
            if (item.getStatus() != WaybillStatusEnum.ARRIVAL.getCode()) {
                throw new GlobalException("存在未到达运单:[" + item.getOutCode() + "]");
            }
            return item.getStatus() == WaybillStatusEnum.ARRIVAL.getCode();
        }).map(LogiWaybill::getOutCode).collect(Collectors.toList());
        inTransit(waybillList, outCodes);
    }

    @Override
    public boolean checkWaybillSign(String scheduleNo) {
        List<LogiWaybill> waybillList = baseMapper.selectByScheduleNo(scheduleNo);
        List<String> outCodes = waybillList.stream().filter(item -> item.getStatus() != WaybillStatusEnum.SIGNATURE.getCode()).map(LogiWaybill::getOutCode).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(outCodes)) {
            throw new GlobalException("运单" + JSONUtil.toJsonStr(outCodes) + "状态不合法,存在运单未签收");
        }
        return true;
    }

    @Override
    public TableDataInfo<LogiWaybillExtVo> stockList(OperationStockQueryBo queryBo) {
        PageInfo<LogiWaybillExtVo> result = startPage(queryBo).doSelectPageInfo(() -> {
            List<LogiWaybillExtVo> voList = baseMapper.selectWaybillList(buildStockList(queryBo));
            fillDate(voList);
        });
        return PageUtils.buildDataInfo(result);
    }

    private QueryWrapper<LogiWaybill> buildStockList(OperationStockQueryBo bo) {
        LogiWaybillQueryBo queryBo = new LogiWaybillQueryBo();
        BeanUtil.copyProperties(bo, queryBo, CopyOptions.create().ignoreNullValue());
        return buildQueryWrapper(queryBo);
    }

    @Override
    public TableDataInfo<LogiWaybillExtVo> receiptList(OperationReceiptQueryBo queryBo) {
        PageInfo<LogiWaybillExtVo> result = startPage(queryBo).doSelectPageInfo(() -> {
            List<LogiWaybillExtVo> voList = baseMapper.selectWaybillList(buildReceiptList(queryBo));
            fillDate(voList);
        });
        return PageUtils.buildDataInfo(result);
    }

    private QueryWrapper<LogiWaybill> buildReceiptList(OperationReceiptQueryBo bo) {
        LogiWaybillQueryBo queryBo = new LogiWaybillQueryBo();
        BeanUtil.copyProperties(bo, queryBo, CopyOptions.create().ignoreNullValue());
        return buildQueryWrapper(queryBo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receipt(OperationReceiptBo receiptBo) {
        LogiWaybill update = new LogiWaybill();
        update.setWaybillId(receiptBo.getWaybillId());
        update.setReceiptAttachments(receiptBo.getReceiptAttachments());
        this.updateById(update);

        // 生成运单跟踪表
        LogiWaybillReceiptLogEditBo editBo = new LogiWaybillReceiptLogEditBo().setReceiptAttachments(receiptBo.getReceiptAttachments());
        editBo.setWaybillId(receiptBo.getWaybillId());
        editBo.setDeptId(SecurityUtils.getDeptId());
        editBo.setCreateBy(SecurityUtils.getPhone());
        editBo.setCreateTime(new Date());
        receiptLogService.insertByAddBo(editBo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(Long waybillId, Integer status) {
        LogiWaybill update = new LogiWaybill().setWaybillId(waybillId).setStatus(status);
        update.setUpdateBy(SecurityUtils.getPhone());
        update.setUpdateTime(new Date());

        LogiWaybillExtVo vo = queryById(waybillId);

        // 增加运单日志
        waybillLogService.addLog(vo.getWaybillId(), status);
        billPushStationMsg(vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.get(status).getInfo(), WaybillStatusEnum.get(status).getNextInfo());
        billPushSms(vo.getWaybillId(), vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.get(status).getInfo(), WaybillStatusEnum.get(status).getNextInfo());
        return this.updateById(update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateScheduleStatus(String scheduleNo, Integer scheduleStatus) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(LogiWaybill::getScheduleStatus, scheduleStatus)
                .set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, new Date())
                .eq(LogiWaybill::getScheduleNo, scheduleNo);
        if (scheduleStatus == ScheduleStatusEnum.CANCEL_SCHEDULE.getCode()) {
            updateWrapper.set(LogiWaybill::getScheduleNo, "");
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.SUBMITED.getCode());
        }
        if (scheduleStatus == ScheduleStatusEnum.SCHEDULED.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.SCHEDULED.getCode());
        }
        if (scheduleStatus == ScheduleStatusEnum.PICKUPING.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.PICKUPING.getCode());
        }
        if (scheduleStatus == ScheduleStatusEnum.ARRIVED.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.ARRIVAL.getCode());
        }
        if (scheduleStatus == ScheduleStatusEnum.DEPARTED.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.DEPARTURE.getCode());
        }
        /*if (scheduleStatus == ScheduleStatusEnum.FINSHED.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.COMPLETED.getCode());
        }*/
        boolean ret = update(null, updateWrapper);
        if (scheduleStatus != ScheduleStatusEnum.FINSHED.getCode()) {
            List<LogiWaybillExtVo> voList = queryList(new LogiWaybillQueryBo().setScheduleNo(scheduleNo));
            voList.forEach(vo -> {
                // 增加运单日志
                waybillLogService.addLog(vo.getWaybillId(), vo.getStatus());
                billPushStationMsg(vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.get(vo.getStatus()).getInfo(), WaybillStatusEnum.get(vo.getStatus()).getNextInfo());
                billPushSms(vo.getWaybillId(), vo.getOutCode(), vo.getCreateBy(), vo.getDeptId(), WaybillStatusEnum.get(vo.getStatus()).getInfo(), WaybillStatusEnum.get(vo.getStatus()).getNextInfo());
            });
        }
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateScheduleStatusByBillId(Long waybillId, Integer scheduleStatus) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        LogiWaybill bill = getById(waybillId);
        updateWrapper.set(LogiWaybill::getScheduleStatus, scheduleStatus)
                .set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, new Date())
                .eq(LogiWaybill::getWaybillId, waybillId);
        if (scheduleStatus == ScheduleStatusEnum.CANCEL_SCHEDULE.getCode()) {
            updateWrapper.set(LogiWaybill::getStatus, WaybillStatusEnum.SUBMITED.getCode());
        }
        boolean ret = update(null, updateWrapper);
        if (scheduleStatus == ScheduleStatusEnum.CANCEL_SCHEDULE.getCode()) {
            checkAndUpdateStatus(bill.getScheduleNo(), WaybillStatusEnum.SUBMITED);
            // 通知众油平台
            List<LogiWaybillOrderRelate> waybillOrderRelateList = waybillOrderRelateService.listByWaybillIds(CollUtil.newArrayList(waybillId));
            for (LogiWaybillOrderRelate logiWaybillOrderRelate : waybillOrderRelateList) {
                if (logiWaybillOrderRelate.getGoodOrderType() == 1) {
                    LogiGoodOrder goodOrder = logiGoodOrderService.getById(logiWaybillOrderRelate.getGoodOrderId());
                    ZhongYouApiUtil.orderChangeCallBack(goodOrder.getPickupOrderNo(), logiWaybillOrderRelate.getWaybillId().toString(),  DateUtil.now(), "");
                }
            }
        }
        //
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelScheduled(Long waybillId) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        LogiWaybill bill = getById(waybillId);
        updateWrapper.set(LogiWaybill::getScheduleStatus, ScheduleStatusEnum.CANCEL_SCHEDULE)
                .set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, new Date())
                .eq(LogiWaybill::getWaybillId, waybillId)
                .set(LogiWaybill::getStatus, WaybillStatusEnum.SUBMITED.getCode());
        boolean ret = update(null, updateWrapper);
        checkAndUpdateStatus(bill.getScheduleNo(), WaybillStatusEnum.SUBMITED);
        // 通知众油平台
        List<LogiWaybillOrderRelate> waybillOrderRelateList = waybillOrderRelateService.listByWaybillIds(CollUtil.newArrayList(waybillId));
        for (LogiWaybillOrderRelate logiWaybillOrderRelate : waybillOrderRelateList) {
            if (logiWaybillOrderRelate.getGoodOrderType() == 1) {
                LogiGoodOrder goodOrder = logiGoodOrderService.getById(logiWaybillOrderRelate.getGoodOrderId());
                ZhongYouApiUtil.orderChangeCallBack(goodOrder.getPickupOrderNo(), logiWaybillOrderRelate.getWaybillId().toString(),  DateUtil.now(), "");
            }
        }
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateDrayageStatusByBillId(Long waybillId, Integer drayageStatus) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(LogiWaybill::getDrayageStatus, drayageStatus)
                .set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, new Date())
                .eq(LogiWaybill::getWaybillId, waybillId);
        return update(null, updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateDrayageStatus(String drayageNo, Integer drayageStatus) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(LogiWaybill::getDrayageStatus, drayageStatus)
                .set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, new Date())
                .eq(LogiWaybill::getDrayageNo, drayageNo);
        if (drayageStatus == DrayageStatusEnum.CANCEL.getCode()) {
            updateWrapper.set(LogiWaybill::getDrayageNo, "");
        }
        return update(null, updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateStatus(String scheduleNo, WaybillStatusEnum billStatus) {
        if (StrUtil.isBlank(scheduleNo)) {
            return;
        }
        List<LogiScheduleExtVo> scheduleExtVos = scheduleService.queryList(new LogiScheduleQueryBo().setScheduleNo(scheduleNo));
        LogiScheduleExtVo scheduleExtVo = scheduleExtVos.get(0);
        Long driverUserId = driverService.getById(scheduleExtVo.getDriverId()).getUserId();

        if (billStatus.getCode() == WaybillStatusEnum.PICKUPING.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.SUBMITED.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.CANCEL.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.SCHEDULED.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.DEPARTURE.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.ARRIVAL.getCode() ||
                billStatus.getCode() == WaybillStatusEnum.COMPLETED.getCode()) {
            //Long count = baseMapper.selectCount(Wrappers.<LogiWaybill>lambdaQuery().eq(LogiWaybill::getScheduleNo, scheduleNo).eq(LogiWaybill::getStatus, billStatus.getCode()));
            Long count = baseMapper.selectCount(Wrappers.<LogiWaybill>lambdaQuery().eq(LogiWaybill::getScheduleNo, scheduleNo));

            /*if (billStatus.getCode() == WaybillStatusEnum.PICKUPED.getCode()) {
                if (count > 0L) {
                    logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                            .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.SCHEDULED.getCode())
                            .eq(LogiSchedule::getScheduleNo, scheduleNo));
                    updateScheduleStatus(scheduleNo, ScheduleStatusEnum.SCHEDULED.getCode());
                }
                return;
            }*/

            Long count1 = baseMapper.selectCount(Wrappers.<LogiWaybill>lambdaQuery().eq(LogiWaybill::getScheduleNo, scheduleNo));
            if (!(count1 > 0L && count.longValue() == count1.longValue())) {
                return;
            }

            /*if (billStatus.getCode() == WaybillStatusEnum.LOADED.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.LOADED.getCode())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.LOADED.getCode());
            }*/

            if (billStatus.getCode() == WaybillStatusEnum.SUBMITED.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.CANCEL_SCHEDULE.getCode())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.CANCEL_SCHEDULE.getInfo(), ScheduleStatusEnum.CANCEL_SCHEDULE.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.CANCEL_SCHEDULE.getInfo(), ScheduleStatusEnum.CANCEL_SCHEDULE.getNext());
            }

            if (billStatus.getCode() == WaybillStatusEnum.SCHEDULED.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.SCHEDULED.getCode())
                        .set(LogiSchedule::getPickupTime, null)
                        .set(LogiSchedule::getDepartTime, null)
                        .set(LogiSchedule::getArriveTime, null)
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.SCHEDULED.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.SCHEDULED.getInfo(), ScheduleStatusEnum.SCHEDULED.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.SCHEDULED.getInfo(), ScheduleStatusEnum.SCHEDULED.getNext());
            }

            if (billStatus.getCode() == WaybillStatusEnum.CANCEL.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.CANCEL_SCHEDULE.getCode())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.CANCEL_SCHEDULE.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.CANCEL_SCHEDULE.getInfo(), ScheduleStatusEnum.CANCEL_SCHEDULE.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.CANCEL_SCHEDULE.getInfo(), ScheduleStatusEnum.CANCEL_SCHEDULE.getNext());

            }

            if (billStatus.getCode() == WaybillStatusEnum.PICKUPING.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.PICKUPING.getCode())
                        .set(LogiSchedule::getPickupTime, new Date())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.PICKUPING.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.PICKUPING.getInfo(), ScheduleStatusEnum.PICKUPING.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.PICKUPING.getInfo(), ScheduleStatusEnum.PICKUPING.getNext());
            }

            if (billStatus.getCode() == WaybillStatusEnum.DEPARTURE.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.DEPARTED.getCode())
                        .set(LogiSchedule::getDepartTime, new Date())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.DEPARTED.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.DEPARTED.getInfo(), ScheduleStatusEnum.DEPARTED.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.DEPARTED.getInfo(), ScheduleStatusEnum.DEPARTED.getNext());
            }

            if (billStatus.getCode() == WaybillStatusEnum.ARRIVAL.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.ARRIVED.getCode())
                        .set(LogiSchedule::getArriveTime, new Date())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.ARRIVED.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.ARRIVED.getInfo(), ScheduleStatusEnum.ARRIVED.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.ARRIVED.getInfo(), ScheduleStatusEnum.ARRIVED.getNext());

            }

            if (billStatus.getCode() == WaybillStatusEnum.COMPLETED.getCode()) {
                logiScheduleService.update(Wrappers.<LogiSchedule>lambdaUpdate()
                        .set(LogiSchedule::getFlowStatus, ScheduleStatusEnum.FINSHED.getCode())
                        .eq(LogiSchedule::getScheduleNo, scheduleNo));
                updateScheduleStatus(scheduleNo, ScheduleStatusEnum.FINSHED.getCode());

                schPushSms(scheduleNo, driverUserId, ScheduleStatusEnum.FINSHED.getInfo(), ScheduleStatusEnum.FINSHED.getNext());
                schPushStationMsg(scheduleNo, driverUserId, ScheduleStatusEnum.FINSHED.getInfo(), ScheduleStatusEnum.FINSHED.getNext());

            }

        }
    }

    private void schPushSms(String scheduleNo, Long driverUserId, String status, String next) {
        if (ObjectUtil.isEmpty(driverUserId)) {
            log.error("司机注册用户ID为空");
            return;
        }
        Map<String, String> params = new HashMap<>();
        params.put("p1", scheduleNo);
        params.put("p2", status);
        params.put("p3", next);
        SmsMessage smsMessage = new SmsMessage().setParamMap(params).setTemplateCode(SmsTemplateEnum.SCHEDULE_NOTIFY.getCode());
        List<LogiSysUser> userList = userService.getNotify(driverUserId, SecurityUtils.PostEnum.DIRECTOR.getCode());
        smsMessage.setPhoneNumbers(userList.stream().map(LogiSysUser::getPhonenumber).collect(Collectors.toList()));
        SmsMsgSend.send(smsMessage);
    }

    private void schPushStationMsg(String scheduleNo, Long driverUserId, String status, String next) {
        if (ObjectUtil.isEmpty(driverUserId)) {
            log.error("司机注册用户ID为空");
            return;
        }
        List<LogiSysUser> userList = userService.getNotify(driverUserId, SecurityUtils.PostEnum.DIRECTOR.getCode());

        SysPublishMsgBo bo = new SysPublishMsgBo();
        bo.setLevel(MsgLevelType.LOW.getType().toString());
        bo.setCreateBy(SecurityUtils.getPhone());
        bo.setMainDeptId(SecurityUtils.getMainDeptId());
        bo.setMsgType(MsgType.TO_DO.getType());
        bo.setContent(String.format("车次[%s]已经[%s]，下一步操作[%s],请及时处理", scheduleNo, status, next));
        bo.setTitle("运单车次代办");
        bo.setBizSys("logi");
        bo.setType(ReceiverType.USER.getType().toString());
        bo.setUserIdList(userList.stream().map(LogiSysUser::getUserId).collect(Collectors.toList()));
        StationMsgSend.send(bo);
    }

    private void billPushStationMsg(String waybillNo, String phone, Long deptId, String status, String next) {
        List<LogiSysUser> userList = userService.getNotify(phone, deptId, SecurityUtils.PostEnum.DIRECTOR.getCode());

        SysPublishMsgBo bo = new SysPublishMsgBo();
        bo.setLevel(MsgLevelType.LOW.getType().toString());
        bo.setCreateBy(SecurityUtils.getPhone());
        bo.setMainDeptId(SecurityUtils.getMainDeptId());
        bo.setMsgType(MsgType.TO_DO.getType());
        bo.setContent(String.format("运单[%s]已经[%s]，下一步操作[%s],请及时处理", waybillNo, status, next));
        bo.setTitle("运单代办");
        bo.setBizSys("logi");
        bo.setType(ReceiverType.USER.getType().toString());
        bo.setUserIdList(userList.stream().map(LogiSysUser::getUserId).collect(Collectors.toList()));
        StationMsgSend.send(bo);
    }

    private void billPushSms(Long billId, String waybillNo, String phone, Long deptId, String status, String next) {
        LogiWaybill bill = getById(billId);
        List<LogiSysUser> userList = userService.getNotify(phone, deptId, SecurityUtils.PostEnum.DIRECTOR.getCode());

        Map<String, String> params = new HashMap<>();
        params.put("p1", waybillNo);
        params.put("p2", status);
        params.put("p3", next);
        SmsMessage smsMessage = new SmsMessage().setParamMap(params).setTemplateCode(SmsTemplateEnum.WAYBILL_NOTIFY.getCode());
        smsMessage.setPhoneNumbers(userList.stream().map(LogiSysUser::getPhonenumber).collect(Collectors.toList()));
        if (StrUtil.isNotBlank(bill.getDeliveryContactTel())) {
            smsMessage.getPhoneNumbers().add(bill.getDeliveryContactTel());
        }
        SmsMsgSend.send(smsMessage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateStatus(List<String> scheduleNos, WaybillStatusEnum billStatus) {
        if (CollUtil.isEmpty(scheduleNos)) {
            return;
        }
        scheduleNos.forEach(t -> {
            checkAndUpdateStatus(t, billStatus);
        });
    }

    /**
     * 新增或修改应收记录
     **/
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdateWaybillReceivable(LogiWaybill waybill, LogiWaybillValueAdd valueAdd, LogiWaybillFee fee) {
        // 结算方式
        Integer settlementMode = null;
        // 付款方id：默认发货方，如果配置了结算方式是到付，那么付款人是收货方
        Long payerId = waybill.getShipId();
        if (ObjectUtil.isNotNull(fee) && ObjectUtil.isNotNull(fee.getSettlementMode())) {
            settlementMode = fee.getSettlementMode();
            if (settlementMode == SettleTypeEnum.pod.getCode()) {
                payerId = waybill.getDeliveryId();
            }
        }
        // 新增或修改应收记录
        LogiWaybillReceivable receivable = logiWaybillReceivableService.getOne(Wrappers.lambdaQuery(LogiWaybillReceivable.class)
                .eq(LogiWaybillReceivable::getWaybillId, waybill.getWaybillId()));
        if (ObjectUtil.isNull(receivable)) {
            receivable = new LogiWaybillReceivable();
            receivable.setDeptId(waybill.getDeptId());
            receivable.setWaybillId(waybill.getWaybillId());
            receivable.setOutCode(waybill.getOutCode());
            receivable.setStatus(SettleStatusEnum.NOT_SETTLE.getCode());
            receivable.setCheckBillStatus(CheckBillStatusEnum.NOT_CHECK.getCode());
            receivable.setRealAmount(BigDecimal.ZERO);
            receivable.setRecordNum(0);
        }
        receivable.setPayerId(payerId);
        receivable.setShipId(waybill.getShipId());
        receivable.setDeliveryId(waybill.getDeliveryId());
        receivable.setTradeAmount(waybill.getTradeTotalFee());
        receivable.setSettlementMode(settlementMode);
        receivable.setReceivableAmount(waybill.getPayableTotalFee());
        receivable.setReceivableBalance(ObjectUtil.defaultIfNull(receivable.getReceivableAmount(), BigDecimal.ZERO).subtract(ObjectUtil.defaultIfNull(receivable.getRealAmount(), BigDecimal.ZERO)));
        logiWaybillReceivableService.saveOrUpdate(receivable);
        // 如果配置了代收货款，则新增或修改代收货款
        addOrUpdateAgentPay(waybill, valueAdd, payerId);
    }

    /**
     * 新增或修改代收货款
     **/
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdateAgentPay(LogiWaybill waybill, LogiWaybillValueAdd valueAdd, Long payerId) {
        if (ObjectUtil.isNotNull(valueAdd) && ObjectUtil.isNotNull(valueAdd.getAgentBusinessFee()) && valueAdd.getAgentBusinessFee().compareTo(BigDecimal.ZERO) > 0) {
            // 查询是否已存在代收货款
            LogiWaybillAgentPay agentPay = logiWaybillAgentPayService.getOne(Wrappers.lambdaQuery(LogiWaybillAgentPay.class)
                    .eq(LogiWaybillAgentPay::getWaybillId, waybill.getWaybillId()));
            if (ObjectUtil.isNull(agentPay)) {
                agentPay = new LogiWaybillAgentPay();
                agentPay.setDeptId(waybill.getDeptId());
                agentPay.setWaybillId(waybill.getWaybillId());
                agentPay.setOutCode(waybill.getOutCode());
                agentPay.setStatus(SettleStatusEnum.NOT_SETTLE.getCode());
                agentPay.setShipId(waybill.getShipId());
                agentPay.setDeliveryId(waybill.getDeliveryId());
                agentPay.setRealAmount(BigDecimal.ZERO);
                agentPay.setRealBalance(BigDecimal.ZERO);
                agentPay.setRecordNum(0);
            }
            // 设置付款方id
            agentPay.setPayerId(payerId);
            // 设置应收余额
            agentPay.setRealBalance(valueAdd.getAgentBusinessFee().add(ObjectUtil.defaultIfNull(valueAdd.getAgentBusinessServiceFee(), BigDecimal.ZERO)).subtract(agentPay.getRealAmount()));
            logiWaybillAgentPayService.saveOrUpdate(agentPay);
        }
    }

    /**
     * 新增或修改应付记录
     **/
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdateWaybillPayable(LogiWaybill waybill) {
        // 获取调度信息
        LogiSchedule schedule = logiScheduleService.getOne(Wrappers.lambdaQuery(LogiSchedule.class)
                .eq(LogiSchedule::getScheduleNo, waybill.getScheduleNo()));
        if (ObjectUtil.isNotNull(schedule) && ObjectUtil.isNotNull(schedule.getCarrierId()) && schedule.getCarrierId() > 0) {
            List<LogiScheduleFeeVo> logiScheduleFeeVos = logiScheduleFeeService.queryList(new LogiScheduleFeeQueryBo().setScheduleId(schedule.getScheduleId()));
            Integer settlementMode = null;
            BigDecimal tradeAmount = BigDecimal.ZERO, payableAmount = BigDecimal.ZERO;
            for (LogiScheduleFeeVo scheduleFeeVo : logiScheduleFeeVos) {
                settlementMode = StrUtil.isNotBlank(scheduleFeeVo.getSettleMode()) ? Integer.valueOf(scheduleFeeVo.getSettleMode()) : null;
                BigDecimal amount = scheduleFeeVo.getApFrt().add(scheduleFeeVo.getApOther());
                tradeAmount = tradeAmount.add(amount);
                payableAmount = payableAmount.add(amount.subtract(scheduleFeeVo.getCodGascard()));
            }
            LogiWaybillPayable payable = logiWaybillPayableService.getOne(Wrappers.lambdaQuery(LogiWaybillPayable.class)
                    .eq(LogiWaybillPayable::getWaybillId, waybill.getWaybillId()));
            if (ObjectUtil.isNull(payable)) {
                payable = new LogiWaybillPayable();
                payable.setDeptId(waybill.getDeptId());
                payable.setWaybillId(waybill.getWaybillId());
                payable.setOutCode(waybill.getOutCode());
                payable.setCarrierId(schedule.getCarrierId());
                payable.setStatus(SettleStatusEnum.NOT_SETTLE.getCode());
                payable.setRealAmount(BigDecimal.ZERO);
                payable.setRecordNum(0);
            }
            payable.setTradeAmount(tradeAmount);
            payable.setSettlementMode(settlementMode);
            payable.setPayableAmount(payableAmount);
            payable.setPayableBalance(payable.getPayableAmount().subtract(payable.getRealAmount()));
            logiWaybillPayableService.saveOrUpdate(payable);
        }
    }

    /**
     * 创建客户对账信息
     **/
    @Transactional(rollbackFor = Exception.class)
    public void addCustomerCheckBill(LogiWaybill waybill) {
        // 获取运单费用
        LogiWaybillFee fee = logiWaybillFeeService.getOne(Wrappers.<LogiWaybillFee>lambdaQuery().eq(LogiWaybillFee::getWaybillId, waybill.getWaybillId()));
        // 付款方id：默认发货方，如果配置了结算方式是到付，那么付款人是收货方
        Long payerId = ObjectUtil.isNotNull(fee) && SettleTypeEnum.pod.getCode() == fee.getSettlementMode() ? waybill.getDeliveryId() : waybill.getShipId();
        // 查询客户名称
        LogiCustomer customer = logiCustomerService.getOne(Wrappers.lambdaQuery(LogiCustomer.class)
                .eq(LogiCustomer::getCustomerId, payerId));
        // 创建客户（付款人）对账信息
        LogiCustomerCheckBill customerCheckBill = logiCustomerCheckBillService.getOne(Wrappers.lambdaQuery(LogiCustomerCheckBill.class)
                .eq(LogiCustomerCheckBill::getCustomerId, customer.getCustomerId()));
        if (ObjectUtil.isNull(customerCheckBill)) {
            customerCheckBill = new LogiCustomerCheckBill();
            customerCheckBill.setDeptId(customer.getDeptId());
            customerCheckBill.setCustomerId(customer.getCustomerId());
            logiCustomerCheckBillService.save(customerCheckBill);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean completed(Long waybillId) {
        LambdaUpdateWrapper<LogiWaybill> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(LogiWaybill::getUpdateBy, SecurityUtils.getPhone())
                .set(LogiWaybill::getUpdateTime, DateUtil.date())
                .eq(LogiWaybill::getWaybillId, waybillId)
                .set(LogiWaybill::getStatus, WaybillStatusEnum.COMPLETED.getCode());
        boolean ret = update(null, updateWrapper);
        LogiWaybill bill = getById(waybillId);
        // 添加或修改客户对账信息
        addCustomerCheckBill(bill);

        // 增加运单日志
        waybillLogService.addLog(waybillId, WaybillStatusEnum.COMPLETED.getCode());
        billPushStationMsg(bill.getOutCode(), bill.getCreateBy(), bill.getDeptId(), WaybillStatusEnum.COMPLETED.getInfo(), WaybillStatusEnum.COMPLETED.getNextInfo());
        billPushSms(bill.getWaybillId(), bill.getOutCode(), bill.getCreateBy(), bill.getDeptId(), WaybillStatusEnum.COMPLETED.getInfo(), WaybillStatusEnum.COMPLETED.getNextInfo());

        return ret;
    }

    // 增加运单控货状态处理
    private void processWaybillControl(Long waybillId) {

        LogiWaybill waybill = getById(waybillId);
        if (Objects.equals(waybill.getCargoControl(), WaybillCargoControlTypeEnum.YES.getType())) {
            LogiWaybillKefuLogEditBo bo = new LogiWaybillKefuLogEditBo()
                    .setWaybillId(waybillId)
                    .setLogType(WaybillKefuLogTypeEnum.LOG_CAGO_CONTROL.getCode())
                    .setRemark("创建运单控货")
                    .setCargoControlStatus(WaybillCargoControlStatueEnum.CONTROL.getType());
            kefuLogService.insertByAddBo(bo);
            return;
        }

        if (Objects.equals(waybill.getCargoControl(), WaybillCargoControlTypeEnum.NO.getType()) && waybill.getCargoControlStatus() > 0) {
            // 如果状态变更了，需要删除自动控货记录
            kefuLogService.remove(Wrappers.<LogiWaybillKefuLog>lambdaQuery()
                    .eq(LogiWaybillKefuLog::getWaybillId, waybillId)
                    .eq(LogiWaybillKefuLog::getLogType, WaybillKefuLogTypeEnum.LOG_CAGO_CONTROL.getCode()));
            LogiWaybill updateCargo = new LogiWaybill().setWaybillId(waybillId).setCargoControlStatus(WaybillCargoControlStatueEnum.UNCONTROL.getType());
            this.updateById(updateCargo);
        }

    }

    /**
     * 查询符合条件已完成的运单（平台用户查看所有）
     **/
    @Override
    public List<LogiWaybill> getCompletedWaybills(Long deptId, String startDate, String endDate) {
        Date startTime = ObjectUtil.isNotNull(startDate) ? DateUtil.beginOfDay(DateUtil.parse(startDate)) : null,
                endTime = ObjectUtil.isNotNull(endDate) ? DateUtil.endOfDay(DateUtil.parse(endDate)) : null;
        LambdaQueryWrapper<LogiWaybill> lqw = Wrappers.lambdaQuery(LogiWaybill.class)
                .eq(LogiWaybill::getStatus, WaybillStatusEnum.COMPLETED.getCode())
                .between(ObjectUtil.isAllNotEmpty(startTime, endTime), LogiWaybill::getCreateTime, startTime, endTime);
        // 部门数据权限过滤
        if (ObjectUtil.isNotNull(deptId) && deptId.intValue() != OrgDeptIdEnum.SYSADMIN.getCode()) {
            SqlUtil.dataPermissionFilter(lqw, deptId);
        }
        return list(lqw);
    }

    /**
     * 删除订单关联的运单信息
     *
     * @author fengxy
     * @date 2024/01/21 0:28
     **/
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrderRelate(Long waybillId) {
        List<LogiWaybillOrderRelate> waybillOrderRelateList = waybillOrderRelateService.listByWaybillIds(CollUtil.newArrayList(waybillId));
        if (CollUtil.isNotEmpty(waybillOrderRelateList)) {
            List<Long> goodOrderIds = waybillOrderRelateList.stream().map(LogiWaybillOrderRelate::getGoodOrderId).collect(Collectors.toList());
            logiGoodOrderService.update(Wrappers.lambdaUpdate(LogiGoodOrder.class)
                    .set(LogiGoodOrder::getWaybillId, null)
                    .set(LogiGoodOrder::getOutCode, null)
                    .in(LogiGoodOrder::getGoodOrderId, goodOrderIds));
        }
    }
}
